package cn.lmxdev.ptms.service.impl;

import cn.lmxdev.ptms.bean.exception.BizException;
import cn.lmxdev.ptms.bean.table.TSpecialtyStudent;
import cn.lmxdev.ptms.bean.table.TSpecialtyTeacher;
import cn.lmxdev.ptms.bean.table.TUser;
import cn.lmxdev.ptms.bean.table.TUserInfo;
import cn.lmxdev.ptms.dao.ISpecialtyStudentDao;
import cn.lmxdev.ptms.dao.ISpecialtyTeacherDao;
import cn.lmxdev.ptms.dao.IUserDao;
import cn.lmxdev.ptms.dao.IUserInfoDao;
import cn.lmxdev.ptms.service.IUserServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class UserServletImpl implements IUserServlet {
    private final IUserDao userDao;
    private final IUserInfoDao userInfoDao;
    private final ISpecialtyTeacherDao specialtyTeacherDao;
    private final ISpecialtyStudentDao specialtyStudentDao;
    private final BCryptPasswordEncoder passwordEncoder;

    @Autowired
    public UserServletImpl(
            IUserDao userDao,
            IUserInfoDao userInfoDao,
            ISpecialtyTeacherDao specialtyTeacherDao,
            ISpecialtyStudentDao specialtyStudentDao
    ) {
        this.userDao = userDao;
        this.userInfoDao = userInfoDao;
        this.specialtyTeacherDao = specialtyTeacherDao;
        this.specialtyStudentDao = specialtyStudentDao;
        this.passwordEncoder = new BCryptPasswordEncoder();
    }

    @Override
    @Transactional
    public TUser get(Long id) {
        return this.userDao.find(id);
    }

    @Override
    @Transactional
    public TUser getByAccount(String account) {
        return this.userDao.findByAccount(account);
    }

    @Override
    @Transactional
    public long add(TUser user) {
        // 判断账号是否已经存在
        TUser userByAccount = this.userDao.findByAccount(user.getAccount());
        if (userByAccount != null && userByAccount.getId() > 0)
            throw new BizException("操作失败，该账号已经存在");

        // 插入数据
        if (!this.userDao.insert(user))
            throw new BizException("操作失败");

        // 添加信息
        if (!this.userInfoDao.insert(user.getUserInfo().setUserId(user.getId())))
            throw new BizException("操作失败，无法添加用户信息");

        // 返回ID
        return user.getId();
    }

    @Override
    @Transactional
    public void register(Long departmentId, Long specialtyId, TUser user) {
        // 添加账号
        this.add(user);

        // 判断角色
        if (user.getUserRoleId() == 5) {
            // 插入专业教师数据
            this.specialtyTeacherDao.insert(new TSpecialtyTeacher()
                    .setSpecialtyId(specialtyId)
                    .setAdviserId(user.getId()));

            // 更改教师角色为指导老师
            this.edit(user.setUserRoleId(4L));
        } else if (user.getUserRoleId() == 6) {
            // 插入专业学生数据
            this.specialtyStudentDao.insert(new TSpecialtyStudent()
                    .setSpecialtyId(specialtyId)
                    .setStudentId(user.getId()));
        }
    }

    @Override
    @Transactional
    public void remove(Long id) {
        // 删除数据
        if (!this.userDao.delete(id))
            throw new BizException("操作失败");
    }

    @Override
    @Transactional
    public void edit(TUser user) {
        // 查询旧数据
        TUser oldUser = this.userDao.find(user.getId());

        // 判断账号是否已经存在
        TUser userByAccount = this.userDao.findByAccount(user.getAccount());
        if (userByAccount != null && !Objects.equals(userByAccount.getId(), user.getId()))
            throw new BizException("操作失败，该账号已经存在");

        // 更新属性
        oldUser.setUserRoleId(user.getUserRoleId())
                .setAccount(user.getAccount())
                .setPassword(user.getPassword());

        // 保存数据
        if (!this.userDao.update(oldUser))
            throw new BizException("操作失败");

        // 查询用户旧信息数据
        TUserInfo oldUserInfo = this.userInfoDao.find(oldUser.getUserInfo().getId());
        if (oldUserInfo == null || oldUserInfo.getId() < 0)
            throw new BizException("操作失败，用户属性不存在");

        // 更新属性
        oldUserInfo.setName(user.getUserInfo().getName())
                .setGender(user.getUserInfo().getGender())
                .setPhone(user.getUserInfo().getPhone())
                .setEmail(user.getUserInfo().getEmail())
                .setQq(user.getUserInfo().getQq())
                .setDingding(user.getUserInfo().getDingding());

        // 保存数据
        if (!this.userInfoDao.update(oldUserInfo))
            throw new BizException("操作失败，无法更新用户属性");
    }

    @Override
    @Transactional
    public void editMyInfo(TUser user) {
        // 查询旧用户数据
        TUser oldUser = this.userDao.find(user.getId());

        // 更新属性
        oldUser.setAccount(user.getAccount())
                .setPassword(user.getPassword());

        // 更新用户属性
        this.edit(oldUser);
    }

    @Override
    @Transactional
    public long count(TUser user) {
        return this.userDao.count(user);
    }

    @Override
    @Transactional
    public List<TUser> list(Long limit, Long page, TUser user) {
        return this.userDao.select(page != null ? (page - 1) * limit : null, limit, user);
    }

    @Override
    @Transactional
    public long countByTeacher(TUser user) {
        return this.userDao.countByTeacher(user);
    }

    @Override
    @Transactional
    public List<TUser> listByTeacher(Long limit, Long page, TUser user) {
        return this.userDao.selectByTeacher(page != null ? (page - 1) * limit : null, limit, user);
    }

    @Override
    @Transactional
    public long departmentHeadCountByTeacher(Long departmentHeadId, TUser user) {
        return this.userDao.departmentHeadCountByTeacher(departmentHeadId, user);
    }

    @Override
    @Transactional
    public List<TUser> departmentHeadListByTeacher(Long departmentHeadId, Long limit, Long page, TUser user) {
        return this.userDao.departmentHeadSelectByTeacher(departmentHeadId, page != null ? (page - 1) * limit : null, limit, user);
    }

    @Override
    @Transactional
    public long specialtyHeadCountByTeacher(Long specialtyHeadId, TUser user) {
        return this.userDao.specialtyHeadCountByTeacher(specialtyHeadId, user);
    }

    @Override
    @Transactional
    public List<TUser> specialtyHeadListByTeacher(Long specialtyHeadId, Long limit, Long page, TUser user) {
        return this.userDao.specialtyHeadSelectByTeacher(specialtyHeadId, page != null ? (page - 1) * limit : null, limit, user);
    }

    @Override
    @Transactional
    public long departmentHeadCountByStudent(Long departmentHeadId, TUser user) {
        return this.userDao.departmentHeadCountByStudent(departmentHeadId, user);
    }

    @Override
    @Transactional
    public List<TUser> departmentHeadListByStudent(Long departmentHeadId, Long limit, Long page, TUser user) {
        return this.userDao.departmentHeadSelectByStudent(departmentHeadId, page != null ? (page - 1) * limit : null, limit, user);
    }

    @Override
    @Transactional
    public long specialtyHeadCountByStudent(Long specialtyHeadId, TUser user) {
        return this.userDao.specialtyHeadCountByStudent(specialtyHeadId, user);
    }

    @Override
    @Transactional
    public List<TUser> specialtyHeadListByStudent(Long specialtyHeadId, Long limit, Long page, TUser user) {
        return this.userDao.specialtyHeadSelectByStudent(specialtyHeadId, page != null ? (page - 1) * limit : null, limit, user);
    }

    @Override
    @Transactional
    public long adviserCountByStudent(Long adviserId, TUser user) {
        return this.userDao.adviserCountByStudent(adviserId, user);
    }

    @Override
    @Transactional
    public List<TUser> adviserListByStudent(Long adviserId, Long limit, Long page, TUser user) {
        return this.userDao.adviserSelectByStudent(adviserId, page != null ? (page - 1) * limit : null, limit, user);
    }

    @Override
    @Transactional
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 加载用户对象
        TUser user = this.userDao.findByAccount(username);
        if (user == null || user.getId() <= 0)
            throw new UsernameNotFoundException("该账号不存在");

        // 加载用户角色
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority(String.format("ROLE_%s", user.getUserRole().getRole().toUpperCase(Locale.ROOT))));
        user.setAuthorities(authorities);

        // 返回用户对象
        return user.setPassword(this.passwordEncoder.encode(user.getPassword()));
    }
}
